package nzb;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;

import jobs.DownloadStatus;

import org.apache.commons.net.nntp.NNTPClient;

import play.Logger;
import play.Play;
import play.cache.Cache;
import yenc.YDecoder;

public class SegmentDownloader extends Thread {

	public static 	boolean 		isDownloading = false;
	public 			String 			currentSegmentBuffer;
	public 			BufferedWriter 	segmentBuffer;
	public			Segment			segmentToDownload;
	public			BufferedReader	segmentDownloaded;
	public			Integer			essais;
	public			String			group;
	public			String			fileName;
	
	public static Integer	NNTP_PORT 			= Integer.parseInt(Play.configuration.get("nntp_port").toString());
	public static String	NNTP_HOST 			= Play.configuration.get("nntp_host").toString();
	public static String	NNTP_USER 			= Play.configuration.get("nntp_user").toString();
	public static String	NNTP_PASS 			= Play.configuration.get("nntp_pass").toString();
	
	public static String	DOWNLOAD_CACHE_DIR	= Play.configuration.get("download_cachedir").toString();
	public static String	DOWNLOAD_DEST_DIR	= Play.configuration.get("download_destinationdir").toString();
	
	private  NNTPClient		nntpClient;
	
	synchronized public NNTPClient getNntpClient() throws SocketException, IOException
	{
		if (this.nntpClient == null) {
			this.nntpClient = new NNTPClient();
		}
		if (!this.nntpClient.isConnected()) {
			this.nntpClient.connect(NNTP_HOST, NNTP_PORT);
			this.nntpClient.authenticate(NNTP_USER, NNTP_PASS);
		}
		
		while(!this.nntpClient.isConnected());
		
		return this.nntpClient;
	}
	
	public SegmentDownloader(Segment segmentToDownload, String group, String fileName) throws UnsupportedEncodingException, FileNotFoundException {
		this.essais = 0;
		this.currentSegmentBuffer = new String();
		this.segmentToDownload = segmentToDownload;
		this.group = group;
		this.fileName = fileName;
	}
	
	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public DownloadStatus getDlStatus() {
		return (DownloadStatus) Cache.get("DOWNLOAD_STATUS");
	}
	
	public void doJob() throws Exception {
		if (getDlStatus() != null) {
			getDlStatus().setCurrentSegmentName(segmentToDownload.getId());
		}
		
		this.segmentBuffer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileDownloader.DOWNLOAD_CACHE_DIR + segmentToDownload.getId()), "ISO-8859-1"));
		System.out.println("Downloading " + this);
		getNntpClient().selectNewsgroup(this.group);
		while(!getNntpClient().isAvailable());
		segmentDownloaded = (BufferedReader) getNntpClient().retrieveArticleBody("<"+ segmentToDownload.getId() +">");
		currentSegmentBuffer = new String();
		char[] currentTest = new char[1024];
		try {
			while (segmentDownloaded.read(currentTest) > 0) {
				this.segmentBuffer.write(currentTest);
			}
		} catch (Exception e) {
			Logger.error("Error when trying to write segment downloaded to disk : ", e);
			segmentBuffer.close();
		} finally {
			segmentBuffer.close();
			try {
				Logger.info("Decoding : " + segmentToDownload.getId() + "...");
				YDecoder.decode(DOWNLOAD_CACHE_DIR + segmentToDownload.getId(), DOWNLOAD_DEST_DIR);
			} catch (Exception e) {
				Logger.error("Erreur when trying do decode, waiting for retry...", e);
				e.printStackTrace();
				sleep(15000);
				Logger.info("Decoding : " + segmentToDownload.getId() + "...");
				YDecoder.decode(DOWNLOAD_CACHE_DIR + segmentToDownload.getId(), DOWNLOAD_DEST_DIR);
			} finally {
				deleteCacheFile();
				getNntpClient().disconnect();
			}
		}
		
	}

	public void deleteCacheFile() {
		Logger.info("Suppression du segment : " + segmentToDownload.getId() + "...");
		File cacheFile = new File(FileDownloader.DOWNLOAD_CACHE_DIR + segmentToDownload.getId());
		cacheFile.delete();
	}
	
	public void setFileStatus() {
		if (getDlStatus() != null) {
			getDlStatus().getFilesStatus().get(this.fileName)[DownloadStatus.CURRENT_SEGMENTS] += 1;
		}
	}
	
	public void run() {
		try {
			this.doJob();
			setFileStatus();
		} catch (Exception e) {
			try {
				Logger.info("Erreur lors de la recuperation du segment : " + segmentToDownload.getId() + " essai : " + essais);
				Logger.error(e.getMessage());
				e.printStackTrace();
				if (essais < 10) {
					segmentBuffer.close();
					getNntpClient().disconnect();
					sleep(100, 0);
					essais++;
					this.run();
				} else {
					throw new Exception();
				}
			} catch (Exception ex) {
				Logger.error("Impossible de recuperer le resultat du serveur : " + ex.getMessage(), ex);
			}
		}
	}
}